package org.db.dao.query;

import java.util.List;

import org.db.dao.BauwerkslinienDAO;
import org.db.dao.HoehenlinienDAO;
import org.db.dao.KruemmungslinienDAO;
import org.db.dao.LageskizzenGVPDAO;
import org.db.dao.LageskizzenWeichenDAO;
import org.db.dao.UeberhoehungslinienDAO;

/**
 * @author Lutz
 * Klasse zum Schreiben der Ergebnisse aus der km- Abfrage in die txt
 *
 */
public class QueryResult {
	
	private double s0;
	private double hoeheBer;
	private String hoeheElement;
	private int uBer;
	private String uElement;
	private double g;
	private String mastpaar1;
	private String mastpaar2;
	
	private BauwerkslinienDAO nearestBauwerkslinienElement;
	
	private HoehenlinienDAO nearestHoehenlinienElement;
	
	private KruemmungslinienDAO nearestKruemmungslinienElement;
	
	private UeberhoehungslinienDAO nearestUeberhoehungslinienElement;
	private UeberhoehungslinienDAO nextUeberhoehungslinienElement;
	private UeberhoehungslinienDAO prevUeberhoehungslinienElement;
	
	private LageskizzenWeichenDAO nearestWeiche;
	
	private List<LageskizzenGVPDAO> nearestGVPs;
	
	public QueryResult(double s0, BauwerkslinienDAO nearestBauwerkslinienElement, HoehenlinienDAO nearestHoehenlinienElement,
			KruemmungslinienDAO nearestKruemmungslinienElement,
			UeberhoehungslinienDAO nearestUeberhoehungslinienElement,
			UeberhoehungslinienDAO nextUeberhoehungslinienElement,
			UeberhoehungslinienDAO prevUeberhoehungslinienElement, LageskizzenWeichenDAO nearestWeiche,
			List<LageskizzenGVPDAO> nearestGVPs) {
		this.s0 = s0;
		this.nearestBauwerkslinienElement = nearestBauwerkslinienElement;
		this.nearestHoehenlinienElement = nearestHoehenlinienElement;
		this.nearestKruemmungslinienElement = nearestKruemmungslinienElement;
		this.nearestUeberhoehungslinienElement = nearestUeberhoehungslinienElement;
		this.nextUeberhoehungslinienElement = nextUeberhoehungslinienElement;
		this.prevUeberhoehungslinienElement = prevUeberhoehungslinienElement;
		this.nearestWeiche = nearestWeiche;
		this.nearestGVPs = nearestGVPs;
	}
	
	public double gets0() {
		return s0;
	}

	public UeberhoehungslinienDAO getPrevUeberhoehungslinienElement() {
		return prevUeberhoehungslinienElement;
	}

	public void setPrevUeberhoehungslinienElement(UeberhoehungslinienDAO prevUeberhoehungslinienElement) {
		this.prevUeberhoehungslinienElement = prevUeberhoehungslinienElement;
	}

	public BauwerkslinienDAO getNearestBauwerkslinienElement() {
		return nearestBauwerkslinienElement;
	}

	public HoehenlinienDAO getNearestHoehenlinienElement() {
		return nearestHoehenlinienElement;
	}

	public KruemmungslinienDAO getNearestKruemmungslinienElement() {
		return nearestKruemmungslinienElement;
	}

	public UeberhoehungslinienDAO getNearestUeberhoehungslinienElement() {
		return nearestUeberhoehungslinienElement;
	}

	public UeberhoehungslinienDAO getNextUeberhoehungslinienElement() {
		return nextUeberhoehungslinienElement;
	}

	public LageskizzenWeichenDAO getNearestWeiche() {
		return nearestWeiche;
	}

	public List<LageskizzenGVPDAO> getNearestGVPs() {
		return nearestGVPs;
	}
	
	public void calculatGleisabstand() {
		List<LageskizzenGVPDAO> nearestGVPs = getNearestGVPs();	
		LageskizzenGVPDAO gvp1;
		LageskizzenGVPDAO gvp2;
		if (nearestGVPs.size() == 2) {
			gvp1 = nearestGVPs.get(0);
			gvp2 = nearestGVPs.get(1);
			double qgl1 = gvp1.getquerGleisLinks();
			double qgr1 = gvp1.getquerGleisRechts();
			double qgl2 = gvp2.getquerGleisLinks();
			double qgr2 = gvp2.getquerGleisRechts();
			double dg = (qgl2-qgr2) - (qgl1-qgr1);
			double a = gvp2.getstationGVPLinks() - gvp1.getstationGVPLinks();
			double b = s0 - gvp1.getstationGVPLinks();
			g = (dg/a)*b + (qgl1 - qgr1);
			mastpaar1 = (gvp1.getpunktNrGVPLinks() + " ; " + gvp1.getpunktNrGVPRechts());
			mastpaar2 = (gvp2.getpunktNrGVPLinks() + " ; " + gvp2.getpunktNrGVPRechts());
		} else if (nearestGVPs.size() == 1) {
			gvp1 = nearestGVPs.get(0);
			g = gvp1.getquerGleisLinks() - gvp1.getquerGleisRechts();
			mastpaar1 = (gvp1.getpunktNrGVPLinks() + " ; " + gvp1.getpunktNrGVPRechts());
		}
	}
	
	public void calculateUeberhoehung() {
		UeberhoehungslinienDAO ueberhoehungsElement = getNearestUeberhoehungslinienElement();
		 if (ueberhoehungsElement != null) {
			 UeberhoehungslinienDAO prevUeberhoehungsElement = getPrevUeberhoehungslinienElement();
			 UeberhoehungslinienDAO nextUeberhoehungsElement = getNextUeberhoehungslinienElement();
			 
			 double sr = ueberhoehungsElement.getStationierungInMeterUe();
			 int up = 0;
			 if(prevUeberhoehungsElement.getUeberhoehungInMM() != 0) {
				  up = prevUeberhoehungsElement.getUeberhoehungInMM();
			 } else {
				 up = 0;
			 }
			 int un = 0;
			 if(nextUeberhoehungsElement.getUeberhoehungInMM() != 0) {
				  un = nextUeberhoehungsElement.getUeberhoehungInMM();
			 }
			 double lr = ueberhoehungsElement.getLaengeRampe();
			 double l2 = nextUeberhoehungsElement.getLaengeRampe();
			 if (lr != 0) {
				 if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RA")) {
					 uElement = ("RA  Länge: " + lr); 
					 uBer = (int) (((s0-sr)*un)/lr);
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RAs")) {
					 uElement = ("RAs  Länge: " + lr); 
					 uBer = (int) ((2*(s0-sr)*(s0-sr)*un)/lr);
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RAss")) {
					 uElement = ("RAss  Länge: " + lr); 
					 uBer = (int) (up-(up/(lr*lr))*(lr-s0)*(lr-s0));
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("REss")) {
					 uElement = ("RAss  Länge: " + lr); 
					 uBer = (int) (up-(up/(lr*lr))*(lr-s0)*(lr-s0));
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RAB")) {
					 uElement = ("RAB  Länge: " + lr); 
					 uBer = (int) (((3*(s0-sr)*(s0-sr))/(lr*lr)-(2*(s0-sr)*(s0-sr)*(s0-sr))/(lr*lr*lr))*un);
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RABs")) {
					 uBer = (int) (up-(up/(lr*lr))*(lr-s0)*(lr-s0));
					 uElement = ("RABs  Länge: " + lr); 
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("REBs")) {
					 uBer = (int) (up-(up/(lr*lr))*(lr-s0)*(lr-s0));
					 uElement = ("REBs  Länge: " + lr); 
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RE")) {
					 uElement = ("RE  Länge: " + lr); 
					 uBer = (int) (up-((s0-sr)*up)/lr);
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("REs")) {
					 uElement = ("REs  Länge: " + lr); 
					 uBer = (int) (up-(2*(s0-sr)*(s0-sr)*up)/lr);
				 } else  if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("REB")) {
					 uElement = ("REB  Länge: " + lr); 
					 uBer = (int) (up-((3*(s0-sr)*(s0-sr))/(lr*lr)-(2*(s0-sr)*(s0-sr)*(s0-sr))/(lr*lr*lr))*up);
				 } else if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RE") && 
						 nextUeberhoehungsElement.getUeberhoehungsrampe().toString().equals("RA")) {
					 uElement = ("Gleisschere RE-RA");
					 uBer = (int) ((up*(lr+l2))*l2);
				 } else if (ueberhoehungsElement.getUeberhoehungsrampe().toString().equals("RA") && 
						 nextUeberhoehungsElement.getUeberhoehungsrampe().toString().equals("RE")) {
					 uElement = ("Gleisschere RA-RE");
					 uBer = (int) ((up*(lr+l2))*l2);
				 }
			 } else if (ueberhoehungsElement.getUeberhoehungInMM() != 0) {
				 uBer = (ueberhoehungsElement.getUeberhoehungInMM());
				 uElement = " konstante Überhöhung"; 
			 }
		 } else {
			 uBer = 0;
		 }
	}
	
	public void calculateHoehe() {
		HoehenlinienDAO hoehenlinienElement = getNearestHoehenlinienElement();
		if(hoehenlinienElement != null){
			double s = hoehenlinienElement.getStationierungInMeter();
			double h = hoehenlinienElement.gethoehe();
			double m1 = hoehenlinienElement.getNeigungAn();
			double m2 = hoehenlinienElement.getNeigungAb();
			int ra = hoehenlinienElement.getRa() != 0 ? hoehenlinienElement.getRa() : 0;
			double lt = hoehenlinienElement.getLt() != 0 ? hoehenlinienElement.getLt() : 0;
			// NW mit Ausrundung
			if (ra != 0) {
				// s0 fällt nicht mit NW zusammen
				if (s0 != s) {
					// s0 kleiner StationNW, innerhalb der Ausrundung
					if ((s-lt) < s0 && s0 < s) {
						if (m2 < m1) {
							hoeheElement = "Ausrundungsbereich - Kuppe";
							hoeheBer = (h-(m1*lt)/1000)+((s0-(s-lt))*m1)/1000+((s0-(s-lt))*(s0-(s-lt)))/(2*ra);	
						} else {
							hoeheElement = "Ausrundungsbereich - Wanne";
							hoeheBer = (h-(m1*lt)/1000)+((s0-(s-lt))*m1)/1000-((s0-(s-lt))*(s0-(s-lt)))/(2*ra);
						}  
						// s0 größer StationNW, innerhalb Ausrundung
					} else if (s < s0 && (s+lt) > s0) { 
						if (m2 < m1) {
							hoeheElement = "Ausrundungsbereich - Kuppe";
							hoeheBer = (h+(m2*lt)/1000)+((s0-(s-lt))*m2)/1000+(((s+lt)-s0)*((s+lt)-s0))/(2*ra);
						} else {
							hoeheElement = "Ausrundungsbereich - Wanne";
							hoeheBer = (h+(m2*lt)/1000)+((s0-(s-lt))*m2)/1000-(((s+lt)-s0)*((s+lt)-s0))/(2*ra);
						} 
						// s0 kleiner StationNW, außerhalb der Ausrundung
					} else if (s0 < (s-lt)) {
						hoeheBer = h-(m1*(s-s0))/1000;
						hoeheElement = "Neigungsbereich";
						// s0 größer StationNW, außerhalb Ausrundung
					} else if (s0 > (s+lt)) {
						hoeheBer = h+(m2*(s0-s))/1000;
						hoeheElement = "Neigungsbereich";
					}
				} else {
					if (m2 < m1) {
						hoeheElement = "Ausrundungsbereich - Kuppe";
						hoeheBer = h-(lt/ra);
					} else {
						hoeheElement = "Ausrundungsbereich - Wanne";
						hoeheBer = h+(lt/ra);
					}
				}
			} else {
				// s0 im Neigungsbereich
				if (s0 != s) {
					if (s0 < s) {
						hoeheBer = h-(m1*(s-s0))/1000;
						hoeheElement = "Neigungsbereich";
					} else {
						hoeheBer = h+(m2*(s0-s))/1000;
						hoeheElement = "Neigungsbereich";
					}
				} else {
					hoeheBer = h;
					hoeheElement = "Neigungswechsel";
				}
			}
		}
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		calculateHoehe();
		calculateUeberhoehung();
		calculatGleisabstand();
		sb.append("\n");
		//für Bauwerkslinie
        sb.append("Bauwerkslinie");
        sb.append("\n");
		sb.append("Bauwerk: ");
		if(nearestBauwerkslinienElement != null){
			sb.append(nearestBauwerkslinienElement.getBauwerk());
		}
		sb.append("\n");
		sb.append("Station von: ");
		if(nearestBauwerkslinienElement != null){
			sb.append(nearestBauwerkslinienElement.getStationierungVonInMeter()).append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if(nearestBauwerkslinienElement != null){
			sb.append(nearestBauwerkslinienElement.getStationierungBisInMeter()).append("m");
		}
		sb.append("\n");
		sb.append("Höhe Bauwerk: ");
		if(nearestBauwerkslinienElement != null){
			sb.append(nearestBauwerkslinienElement.getHoeheInMeter()).append("m");
		}
		sb.append("\n");
		sb.append("Besonderheiten: ");
		if(nearestBauwerkslinienElement != null){
			sb.append(nearestBauwerkslinienElement.getBesonderheiten());
		}
		sb.append("\n");
		sb.append("\n");
		//Für Höhenlinie
		sb.append("Höhenlinie");
		sb.append("\n");
		sb.append("Höhe: ");
		if (nearestHoehenlinienElement != null) {
			sb.append(hoeheBer);
		}
		sb.append("\n");
		sb.append("Element: ");
		if (nearestHoehenlinienElement != null) {
			sb.append(hoeheElement); 
		}
		sb.append("\n");
		sb.append("\n");
		//Für Überhöhungslinie
		sb.append("Überhöhungslinie");
		sb.append("\n");
		sb.append("Überhöhung: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(uBer);
		} else {
			sb.append("0");
		}
		sb.append("\n");
		sb.append("Element: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(uElement);
		}
		sb.append("\n");
		sb.append("Station von: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(nearestUeberhoehungslinienElement.getStationierungInMeterUe()).append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if (nearestUeberhoehungslinienElement != null) {
			sb.append(nearestUeberhoehungslinienElement.getEndstationierungInMeterUE()).append("m");
		}
		sb.append("\n");
		sb.append("\n");
		//Für Krümmungslinie
		sb.append("Krümmungslinie");	
		sb.append("Element: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(nearestKruemmungslinienElement.getElement());
		}
		sb.append("\n");
		sb.append("Station von: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(nearestKruemmungslinienElement.getStationierungInMeter()).append("m");
		}
		sb.append("\n");
		sb.append("Station bis: ");
		if (nearestKruemmungslinienElement != null) {
			sb.append(nearestKruemmungslinienElement.getEndstationierungInMeter()).append("m");
		}
		sb.append("\n");
		sb.append("\n");
		//Für Lageskizze
		sb.append("Lageskizze");
		sb.append("\n");
		sb.append("Gleisabstand: ");
		if (g != 0) {
			sb.append(g);
		}
		sb.append("\n");
		if (nearestGVPs != null) {
			sb.append("Mastpaar 1: " + mastpaar1);
		}
		sb.append("\n");
		if (nearestGVPs.size() == 2) {
			sb.append("Mastpaar 2: " + mastpaar2);
		}
		sb.append("");
		return sb.toString();
	}

}
